﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//                          ИСПОЛЬЗОВАНИЕ ФОРМЫ                               //
//
// Форма предназначена для выбора объектов метаданных конфигурации и передачи
// выбранных их списка в вызывающую среду.
//
// Параметры вызова:
// КоллекцииВыбираемыхОбъектовМетаданных - СписокЗначений - фактически фильтр
//				по типам объектов метаданных, которые могут быть выбраны.
//				Например:
//					ФильтрПоСсылочнымМетаданным = Новый СписокЗначений;
//					ФильтрПоСсылочнымМетаданным.Добавить("Справочники");
//					ФильтрПоСсылочнымМетаданным.Добавить("Документы");
//				Позволяет выбирать только объекты метаданных справочники и документы.
// ВыбранныеОбъектыМетаданных - СписокЗначений - уже выбранные объекты метаданных.
//				В дереве метаданных такие объекты будут отмечены флажком выбора.
//				Может быть полезным для установки объектов метаданных выбора по умолчанию
//				или переустановки уже установленного списка.
// РодительскиеПодсистемы - СписокЗначений - подсистемы, только подчиненные подсистемы которых
// 				будут отображаться в форме (спец. для помощника внедрения БСП). 
// ТолькоПодсистемыСКИ - булево - признак того, что в списке выбора будут только те подсистемы, 
//				которые включены в командный интерфейс (спец. для помощника внедрения БСП).
// ВыборЕдинственного - булево - признак того, что выбирается единственный объект метаданных.
//              При этом пометка нескольких будет невозможна, кроме того двойной клик по строке
//              с объектом метаданных осуществит выбор.
// НачальноеЗначениеВыбора - Строка - полное имя метаданных, на котором будет спозиционирован
//              список при открытии формы.
//

#Область ОписаниеПеременных

&НаСервере
Перем ПодчиненныеСправочники;

#КонецОбласти

#Область ОбработчикиСобытийФормы

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	УстановитьУсловноеОформление();
	
	ВыбиратьКоллекцииКогдаВыбраныВсеОбъекты = Параметры.ВыбиратьКоллекцииКогдаВыбраныВсеОбъекты;
	ЗапоминатьРазделыВыбранныхОбъектов      = Параметры.ЗапоминатьРазделыВыбранныхОбъектов;
	КоллекцииВыбираемыхОбъектовМетаданных   = Параметры.КоллекцииВыбираемыхОбъектовМетаданных;
	РодительскиеПодсистемы                  = Параметры.РодительскиеПодсистемы;
	ФильтрПоОбъектамМетаданных              = Параметры.ФильтрПоОбъектамМетаданных;
	УникальныйИдентификаторИсточник         = Параметры.УникальныйИдентификаторИсточник;
	СпособГруппировкиОбъектов               = Параметры.СпособГруппировкиОбъектов;
	ВыбранныеОбъектыМетаданных              = ОбщегоНазначения.СкопироватьРекурсивно(Параметры.ВыбранныеОбъектыМетаданных);
	
	ВыбиратьСсылки          = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры, "ВыбиратьСсылки", Ложь);
	ТолькоПодсистемыСКИ     = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры, "ТолькоПодсистемыСКИ", Ложь);
	ВыборЕдинственного      = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры, "ВыборЕдинственного", Ложь);
	НачальноеЗначениеВыбора = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Параметры, "НачальноеЗначениеВыбора", Ложь);
	
	ЗаполнитьВыбранныеОбъектыМетаданных();
	
	Если ФильтрПоОбъектамМетаданных.Количество() > 0 Тогда
		КоллекцииВыбираемыхОбъектовМетаданных.Очистить();
		Для Каждого ОбъектМетаданныхПолноеИмя Из ФильтрПоОбъектамМетаданных Цикл
			ИмяБазовогоТипа = ОбщегоНазначения.ИмяБазовогоТипаПоОбъектуМетаданных(
				ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ОбъектМетаданныхПолноеИмя.Значение));
			Если КоллекцииВыбираемыхОбъектовМетаданных.НайтиПоЗначению(ИмяБазовогоТипа) = Неопределено Тогда
				КоллекцииВыбираемыхОбъектовМетаданных.Добавить(ИмяБазовогоТипа);
			КонецЕсли;
		КонецЦикла;
	ИначеЕсли ВыбиратьСсылки Тогда
		МодульИдентификаторыОбъектовМетаданных = ОбщегоНазначения.ОбщийМодуль(
			"Справочники.ИдентификаторыОбъектовМетаданных");
		ДопустимыеКоллекции = МодульИдентификаторыОбъектовМетаданных.ДопустимыеКоллекции();
		Если Не ЗначениеЗаполнено(КоллекцииВыбираемыхОбъектовМетаданных) Тогда
			Для Каждого ДопустимаяКоллекция Из ДопустимыеКоллекции Цикл
				КоллекцииВыбираемыхОбъектовМетаданных.Добавить(ДопустимаяКоллекция);
			КонецЦикла;
		Иначе
			ПодходящиеКоллекции = Новый СписокЗначений;
			Для Каждого ЭлементСписка Из КоллекцииВыбираемыхОбъектовМетаданных Цикл
				Если ДопустимыеКоллекции.Найти(ЭлементСписка.Значение) <> Неопределено Тогда
					ПодходящиеКоллекции.Добавить().Значение = ЭлементСписка.Значение;
				КонецЕсли;
			КонецЦикла;
			Если ПодходящиеКоллекции.Количество() = 0 Тогда
				ПодходящиеКоллекции.Добавить().Значение = ДопустимыеКоллекции[0];
			КонецЕсли;
			КоллекцииВыбираемыхОбъектовМетаданных = ПодходящиеКоллекции;
		КонецЕсли;
	КонецЕсли;
	
	Если ТолькоПодсистемыСКИ Тогда
		СписокПодсистем = Метаданные.Подсистемы;
		ЗаполнитьСписокПодсистем(СписокПодсистем);
	КонецЕсли;
	
	Если ВыборЕдинственного Тогда
		Элементы.Пометка.Видимость = Ложь;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Параметры.Заголовок) Тогда
		АвтоЗаголовок = Ложь;
		Заголовок = Параметры.Заголовок;
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(НачальноеЗначениеВыбора)
		И ВыборЕдинственного
		И Параметры.ВыбранныеОбъектыМетаданных.Количество() = 1 Тогда
		НачальноеЗначениеВыбора = Параметры.ВыбранныеОбъектыМетаданных[0].Значение;
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(СпособГруппировкиОбъектов) Тогда
		СпособГруппировкиОбъектов = "ПоРазделам";
		
	ИначеЕсли СпособГруппировкиОбъектов = "ПоВидам"
	      Или СпособГруппировкиОбъектов = "ПоРазделам" Тогда
		
		Элементы.СпособГруппировкиОбъектов.Видимость = Ложь;
	Иначе
		СпособыГруппировки = СтрРазделить(Параметры.СпособГруппировкиОбъектов, ",", Ложь);
		Если СпособыГруппировки[0] = "ПоВидам" Тогда
			СпособГруппировкиОбъектов = "ПоВидам";
		Иначе
			СпособГруппировкиОбъектов = "ПоРазделам";
		КонецЕсли;
	КонецЕсли;
	
	Если ОбщегоНазначения.ЭтоМобильныйКлиент() Тогда
		ПоложениеКоманднойПанели = ПоложениеКоманднойПанелиФормы.Верх;
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
	
	ЗаполнитьДеревоОбъектов(Истина);
	
КонецПроцедуры

&НаСервере
Процедура ПередЗагрузкойДанныхИзНастроекНаСервере(Настройки)
	
	Если Не Элементы.СпособГруппировкиОбъектов.Видимость
	 Или Настройки["СпособГруппировкиОбъектов"] <> "ПоВидам"
	   И Настройки["СпособГруппировкиОбъектов"] <> "ПоРазделам" Тогда
		
		Настройки.Вставить("СпособГруппировкиОбъектов", СпособГруппировкиОбъектов);
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область ОбработчикиСобытийЭлементовШапкиФормы

// Процедура обработчик события нажатия на поле "Пометка" дерева формы.
&НаКлиенте
Процедура ПометкаПриИзменении(Элемент)
	
	ПометкаВыполнялась = Истина;
	ПриПометкеЭлементаДерева(ТекущийЭлемент.ТекущиеДанные);
	
КонецПроцедуры

&НаКлиенте
Процедура РежимВыбораПриИзменении(Элемент)
	
	Если ПометкаВыполнялась Тогда
		АдресаВыбранныхОбъектов.Очистить();
		ОбновитьКоллекциюВыбранныеОбъектыМетаданных();
	КонецЕсли;
	
	ЗаполнитьДеревоОбъектов();
	
КонецПроцедуры

#КонецОбласти

#Область ОбработчикиСобытийЭлементовТаблицыФормыДеревоОбъектовМетаданных

&НаКлиенте
Процедура ДеревоОбъектовМетаданныхВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)

	Если ВыборЕдинственного Тогда
		
		ВыбратьВыполнить();
		
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область ОбработчикиКомандФормы

&НаКлиенте
Процедура ВыбратьВыполнить()
	
	Если ВыборЕдинственного Тогда
		
		ТекДанные = Элементы.ДеревоОбъектовМетаданных.ТекущиеДанные;
		Если ТекДанные <> Неопределено
			И ТекДанные.ЭтоОбъектМетаданных Тогда
			
			ВыбранныеОбъектыМетаданных.Очистить();
			ВыбранныеОбъектыМетаданных.Добавить(ТекДанные.ПолноеИмя, ТекДанные.Представление);
			
		Иначе
			Возврат;
		КонецЕсли;
	Иначе
		ОбновитьКоллекциюВыбранныеОбъектыМетаданных();
	КонецЕсли;
	
	Если ВыбиратьСсылки Тогда
		ВыбратьСсылки(ВыбранныеОбъектыМетаданных);
	КонецЕсли;
	
	Если ОписаниеОповещенияОЗакрытии = Неопределено Тогда
		Оповестить("ВыборОбъектовМетаданных", ВыбранныеОбъектыМетаданных, УникальныйИдентификаторИсточник);
	КонецЕсли;
	
	Закрыть(ВыбранныеОбъектыМетаданных);
	
КонецПроцедуры

&НаКлиенте
Процедура ЗакрытьВыполнить()
	
	Закрыть();
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

&НаСервере
Процедура ЗаполнитьВыбранныеОбъектыМетаданных()
	
	ОбъектыМетаданных = ВыбранныеОбъектыМетаданных.ВыгрузитьЗначения();
	
	Если ЗапоминатьРазделыВыбранныхОбъектов
		И ВыбранныеОбъектыМетаданных.Количество() > 0 И СтрНачинаетсяС(ВыбранныеОбъектыМетаданных[0].Представление, "./") Тогда
		Для Каждого Элемент Из ВыбранныеОбъектыМетаданных Цикл
			АдресаВыбранныхОбъектов.Добавить(Элемент.Представление, Элемент.Значение);
		КонецЦикла;
	КонецЕсли;
	
	Если Не ВыбиратьСсылки Тогда
		Возврат;
	КонецЕсли;
	
	Ссылки = Новый Массив;
	
	Для Каждого ОбъектМетаданных Из ОбъектыМетаданных Цикл 
		
		Если ТипЗнч(ОбъектМетаданных) = Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")
			Или ТипЗнч(ОбъектМетаданных) = Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений") Тогда 
			
			Ссылки.Добавить(ОбъектМетаданных);
		КонецЕсли;
		
	КонецЦикла;
	
	Если Ссылки.Количество() = 0 Тогда 
		Возврат;
	КонецЕсли;
	
	ИменаОбъектовМетаданных = ОбщегоНазначения.ЗначениеРеквизитаОбъектов(Ссылки, "ПолноеИмя");
	
	Для Каждого ЭлементСписка Из ВыбранныеОбъектыМетаданных Цикл 
		
		ИмяОбъектаМетаданных = ИменаОбъектовМетаданных[ЭлементСписка.Значение];
		Если ИмяОбъектаМетаданных <> Неопределено Тогда 
			ЭлементСписка.Значение = ИмяОбъектаМетаданных;
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьСписокПодсистем(СписокПодсистем) 
	Для Каждого Подсистема Из СписокПодсистем Цикл
		Если Подсистема.ВключатьВКомандныйИнтерфейс Тогда
			ЭлементыПодсистемСКоманднымИнтерфейсом.Добавить(Подсистема.ПолноеИмя());
		КонецЕсли;
		
		Если Подсистема.Подсистемы.Количество() > 0 Тогда
			ЗаполнитьСписокПодсистем(Подсистема.Подсистемы);
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры

// Процедура заполняет дерево значений объектов конфигурации.
// Если список значений "КоллекцииВыбираемыхОбъектовМетаданных" не пуст, тогда
// дерево будет ограничено переданным списком коллекций объектов метаданных.
//  Если объекты метаданных в сформированном дереве будут найдены в списке значений
// ВыбранныеОбъектыМетаданных, тогда они будут помечены, как выбранные.
//
&НаСервере
Процедура ДеревоОбъектовМетаданныхЗаполнить()
	
	ДеревоОбъектовМетаданных.ПолучитьЭлементы().Очистить();
	
	КоллекцииОбъектовМетаданных = Новый ТаблицаЗначений;
	КоллекцииОбъектовМетаданных.Колонки.Добавить("Имя");
	КоллекцииОбъектовМетаданных.Колонки.Добавить("Синоним");
	КоллекцииОбъектовМетаданных.Колонки.Добавить("Картинка");
	КоллекцииОбъектовМетаданных.Колонки.Добавить("ЭтоКоллекцияОбщие");
	КоллекцииОбъектовМетаданных.Колонки.Добавить("ПолноеИмя");
	КоллекцииОбъектовМетаданных.Колонки.Добавить("Родитель");
	
	КоллекцииОбъектовМетаданных_НоваяСтрока("Подсистемы",                   НСтр("ru = 'Подсистемы'"),                     БиблиотекаКартинок.МетаданныеПодсистемы,                   Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ОбщиеМодули",                  НСтр("ru = 'Общие модули'"),                   БиблиотекаКартинок.МетаданныеОбщиеМодули,                  Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ПараметрыСеанса",              НСтр("ru = 'Параметры сеанса'"),               БиблиотекаКартинок.МетаданныеПараметрыСеанса,              Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("Роли",                         НСтр("ru = 'Роли'"),                           БиблиотекаКартинок.МетаданныеРоли,                         Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ОбщиеРеквизиты",               НСтр("ru = 'Общие реквизиты'"),                БиблиотекаКартинок.МетаданныеОбщиеРеквизиты,               Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ПланыОбмена",                  НСтр("ru = 'Планы обмена'"),                   БиблиотекаКартинок.МетаданныеПланыОбмена,                  Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("КритерииОтбора",               НСтр("ru = 'Критерии отбора'"),                БиблиотекаКартинок.МетаданныеКритерииОтбора,               Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ПодпискиНаСобытия",            НСтр("ru = 'Подписки на события'"),            БиблиотекаКартинок.МетаданныеПодпискиНаСобытия,            Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("РегламентныеЗадания",          НСтр("ru = 'Регламентные задания'"),           БиблиотекаКартинок.МетаданныеРегламентныеЗадания,          Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ФункциональныеОпции",          НСтр("ru = 'Функциональные опции'"),           БиблиотекаКартинок.МетаданныеФункциональныеОпции,          Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ПараметрыФункциональныхОпций", НСтр("ru = 'Параметры функциональных опций'"), БиблиотекаКартинок.МетаданныеПараметрыФункциональныхОпций, Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ХранилищаНастроек",            НСтр("ru = 'Хранилища настроек'"),             БиблиотекаКартинок.МетаданныеХранилищаНастроек,            Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ОбщиеФормы",                   НСтр("ru = 'Общие формы'"),                    БиблиотекаКартинок.МетаданныеОбщиеФормы,                   Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ОбщиеКоманды",                 НСтр("ru = 'Общие команды'"),                  БиблиотекаКартинок.МетаданныеОбщиеКоманды,                 Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ГруппыКоманд",                 НСтр("ru = 'Группы команд'"),                  БиблиотекаКартинок.МетаданныеГруппыКоманд,                 Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("Интерфейсы",                   НСтр("ru = 'Интерфейсы'"),                     Неопределено,                                              Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ОбщиеМакеты",                  НСтр("ru = 'Общие макеты'"),                   БиблиотекаКартинок.МетаданныеОбщиеМакеты,                  Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ОбщиеКартинки",                НСтр("ru = 'Общие картинки'"),                 БиблиотекаКартинок.МетаданныеОбщиеКартинки,                Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ПакетыXDTO",                   НСтр("ru = 'XDTO-пакеты'"),                    БиблиотекаКартинок.МетаданныеПакетыXDTO,                   Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("WebСервисы",                   НСтр("ru = 'Web-сервисы'"),                    БиблиотекаКартинок.МетаданныеWebСервисы,                   Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("HTTPСервисы",                  НСтр("ru = 'HTTP-сервисы'"),                   БиблиотекаКартинок.МетаданныеHTTPСервисы,                  Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("WSСсылки",                     НСтр("ru = 'WS-ссылки'"),                      БиблиотекаКартинок.МетаданныеWSСсылки,                     Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("Стили",                        НСтр("ru = 'Стили'"),                          БиблиотекаКартинок.МетаданныеСтили,                        Истина, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("Языки",                        НСтр("ru = 'Языки'"),                          БиблиотекаКартинок.МетаданныеЯзыки,                        Истина, КоллекцииОбъектовМетаданных);
	
	КоллекцииОбъектовМетаданных_НоваяСтрока("Константы",                    НСтр("ru = 'Константы'"),                      БиблиотекаКартинок.МетаданныеКонстанты,               Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("Справочники",                  НСтр("ru = 'Справочники'"),                    БиблиотекаКартинок.МетаданныеСправочники,             Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("Документы",                    НСтр("ru = 'Документы'"),                      БиблиотекаКартинок.МетаданныеДокументы,               Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ЖурналыДокументов",            НСтр("ru = 'Журналы документов'"),             БиблиотекаКартинок.МетаданныеЖурналыДокументов,       Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("Перечисления",                 НСтр("ru = 'Перечисления'"),                   БиблиотекаКартинок.МетаданныеПеречисления,            Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("Отчеты",                       НСтр("ru = 'Отчеты'"),                         БиблиотекаКартинок.МетаданныеОтчеты,                  Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("Обработки",                    НСтр("ru = 'Обработки'"),                      БиблиотекаКартинок.МетаданныеОбработки,               Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ПланыВидовХарактеристик",      НСтр("ru = 'Планы видов характеристик'"),      БиблиотекаКартинок.МетаданныеПланыВидовХарактеристик, Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ПланыСчетов",                  НСтр("ru = 'Планы счетов'"),                   БиблиотекаКартинок.МетаданныеПланыСчетов,             Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ПланыВидовРасчета",            НСтр("ru = 'Планы видов расчета'"),            БиблиотекаКартинок.МетаданныеПланыВидовРасчета,       Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("РегистрыСведений",             НСтр("ru = 'Регистры сведений'"),              БиблиотекаКартинок.МетаданныеРегистрыСведений,        Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("РегистрыНакопления",           НСтр("ru = 'Регистры накопления'"),            БиблиотекаКартинок.МетаданныеРегистрыНакопления,      Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("РегистрыБухгалтерии",          НСтр("ru = 'Регистры бухгалтерии'"),           БиблиотекаКартинок.МетаданныеРегистрыБухгалтерии,     Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("РегистрыРасчета",              НСтр("ru = 'Регистры расчета'"),               БиблиотекаКартинок.МетаданныеРегистрыРасчета,         Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("БизнесПроцессы",               НСтр("ru = 'Бизнес-процессы'"),                БиблиотекаКартинок.МетаданныеБизнесПроцессы,          Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("Задачи",                       НСтр("ru = 'Задачи'"),                         БиблиотекаКартинок.МетаданныеЗадачи,                  Ложь, КоллекцииОбъектовМетаданных);
	КоллекцииОбъектовМетаданных_НоваяСтрока("ВнешниеИсточникиДанных",       НСтр("ru = 'Внешние источники данных'"),       БиблиотекаКартинок.МетаданныеВнешниеИсточникиДанных,  Ложь, КоллекцииОбъектовМетаданных);
	
	// Создание предопределенных элементов.
	ПараметрыЭлемента = ПараметрыЭлементаДереваОбъектовМетаданных();
	ПараметрыЭлемента.Имя = Метаданные.Имя;
	ПараметрыЭлемента.Синоним = Метаданные.Синоним;
	ПараметрыЭлемента.Картинка = БиблиотекаКартинок.МетаданныеКонфигурация;
	ПараметрыЭлемента.Родитель = ДеревоОбъектовМетаданных;
	ЭлементКонфигурация = НоваяСтрокаДерева(ПараметрыЭлемента);
	
	ПараметрыЭлемента = ПараметрыЭлементаДереваОбъектовМетаданных();
	ПараметрыЭлемента.Имя = "Общие";
	ПараметрыЭлемента.Синоним = НСтр("ru = 'Общие'");
	ПараметрыЭлемента.Картинка = БиблиотекаКартинок.МетаданныеОбщие;
	ПараметрыЭлемента.Родитель = ЭлементКонфигурация;
	ЭлементОбщие = НоваяСтрокаДерева(ПараметрыЭлемента);
	
	// Заполнение дерева объектов метаданных.
	Для Каждого Строка Из КоллекцииОбъектовМетаданных Цикл
		Если КоллекцииВыбираемыхОбъектовМетаданных.Количество() = 0
			Или КоллекцииВыбираемыхОбъектовМетаданных.НайтиПоЗначению(Строка.Имя) <> Неопределено Тогда
			Строка.Родитель = ?(Строка.ЭтоКоллекцияОбщие, ЭлементОбщие, ЭлементКонфигурация);
			ДобавитьЭлементДереваОбъектовМетаданных(Строка, ?(Строка.Имя = "Подсистемы", Метаданные.Подсистемы, Неопределено));
		КонецЕсли;
	КонецЦикла;
	
	Если ЭлементОбщие.ПолучитьЭлементы().Количество() = 0 Тогда
		ЭлементКонфигурация.ПолучитьЭлементы().Удалить(ЭлементОбщие);
	КонецЕсли;
	
КонецПроцедуры

// Возвращает новую структуру параметров элемента дерева объектов метаданных.
//
// Возвращаемое значение:
//   Структура:
//     Имя           - Строка - имя родительского элемента.
//     Синоним       - Строка - синоним родительского элемента.
//     Пометка       - Булево - начальная пометка коллекции или объекта метаданных.
//     Картинка      - Картинка - картинка родительского элемента.
//     Родитель        - ссылка на элемента дерева значений, который является корнем
//                       для добавляемого элемента.
//
&НаСервере
Функция ПараметрыЭлементаДереваОбъектовМетаданных()
	
	СтруктураПараметров = Новый Структура;
	СтруктураПараметров.Вставить("Имя", "");
	СтруктураПараметров.Вставить("ПолноеИмя", "");
	СтруктураПараметров.Вставить("Синоним", "");
	СтруктураПараметров.Вставить("Пометка", 0);
	СтруктураПараметров.Вставить("Картинка", Неопределено);
	СтруктураПараметров.Вставить("Родитель", Неопределено);
	
	Возврат СтруктураПараметров;
	
КонецФункции

// Добавляет новую строку в дерево значений формы (дерево),
// а также заполняет полный набор строк из метаданных по переданному параметру.
//
// Если параметр Подсистемы заполнен, то вызывается рекурсивно для всех дочерних подсистем.
//
// Параметры:
//   ПараметрыЭлемента - Структура:
//     * Имя           - Строка - имя родительского элемента.
//     * Синоним       - Строка - синоним родительского элемента.
//     * Пометка       - Булево - начальная пометка коллекции или объекта метаданных.
//     * Картинка      - Картинка - картинка родительского элемента.
//     * Родитель      - ДанныеФормыЭлементДерева:
//         ** Имя - Строка.
//         ** Представление - Строка.
//         ** Картинка - Картинка.
//         ** ПолноеИмя - Строка.
//         ** ЭтоОбъектМетаданных - Булево.
//         ** Пометка - Булево.
//   Подсистемы - КоллекцияОбъектовМетаданных - если заполнен, то содержит значение Метаданные.Подсистемы (коллекцию элементов).
//   Проверять       - Булево - признак проверки на принадлежность родительским подсистемам.
// 
// Возвращаемое значение:
//  ДанныеФормыЭлементДерева
//
&НаСервере
Функция ДобавитьЭлементДереваОбъектовМетаданных(ПараметрыЭлемента, Подсистемы = Неопределено, Проверять = Истина)
	
	// Проверка на наличие командного интерфейса только в листьях дерева.
	Если Подсистемы <> Неопределено  И Параметры.Свойство("ТолькоПодсистемыСКИ") 
		И Не ПустаяСтрока(ПараметрыЭлемента.ПолноеИмя) 
		И ЭлементыПодсистемСКоманднымИнтерфейсом.НайтиПоЗначению(ПараметрыЭлемента.ПолноеИмя) = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Если Подсистемы = Неопределено Тогда
		
		Если Метаданные[ПараметрыЭлемента.Имя].Количество() = 0 Тогда
			
			// Если нет ни одного объекта метаданных из нужной ветки. 
			// Например, нет ни одного регистра бухгалтерии,
			// то корень "Регистры бухгалтерии" добавлять не нужно.
			Возврат Неопределено;
			
		КонецЕсли;
		
		НоваяСтрока = НоваяСтрокаДерева(ПараметрыЭлемента, Подсистемы <> Неопределено И Подсистемы <> Метаданные.Подсистемы);
		НоваяСтрока.ЭтоКоллекцияОбъектов = Истина;
		
		Для Каждого ЭлементКоллекцииМетаданных Из Метаданные[ПараметрыЭлемента.Имя] Цикл
			
			Если ФильтрПоОбъектамМетаданных.Количество() > 0
				И ФильтрПоОбъектамМетаданных.НайтиПоЗначению(ЭлементКоллекцииМетаданных.ПолноеИмя()) = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			ПараметрыЭлемента = ПараметрыЭлементаДереваОбъектовМетаданных();
			ПараметрыЭлемента.Имя = ЭлементКоллекцииМетаданных.Имя;
			ПараметрыЭлемента.ПолноеИмя = ЭлементКоллекцииМетаданных.ПолноеИмя();
			ПараметрыЭлемента.Синоним = ЭлементКоллекцииМетаданных.Синоним;
			ПараметрыЭлемента.Родитель = НоваяСтрока;
			ПараметрыЭлемента.Картинка = ?(ПараметрыЭлемента.Родитель.Картинка <> Неопределено,
				ПараметрыЭлемента.Родитель.Картинка, КартинкаВКонфигураторе(ЭлементКоллекцииМетаданных));
			НоваяСтрокаДерева(ПараметрыЭлемента, Истина);
		КонецЦикла;
		
		Возврат НоваяСтрока;
		
	КонецЕсли;
		
	Если Подсистемы.Количество() = 0 И ПараметрыЭлемента.Имя = "Подсистемы" Тогда
		// Если нет ни одной подсистемы, то корень "Подсистемы" добавлять не нужно.
		Возврат Неопределено;
	КонецЕсли;
	
	НоваяСтрока = НоваяСтрокаДерева(ПараметрыЭлемента, Подсистемы <> Неопределено И Подсистемы <> Метаданные.Подсистемы);
	НоваяСтрока.ЭтоКоллекцияОбъектов = (Подсистемы = Метаданные.Подсистемы);
	
	Для Каждого ЭлементКоллекцииМетаданных Из Подсистемы Цикл
		
		Если Не Проверять
			Или РодительскиеПодсистемы.Количество() = 0
			Или РодительскиеПодсистемы.НайтиПоЗначению(ЭлементКоллекцииМетаданных.Имя) <> Неопределено Тогда
			
			ПараметрыЭлемента = ПараметрыЭлементаДереваОбъектовМетаданных();
			ПараметрыЭлемента.Имя = ЭлементКоллекцииМетаданных.Имя;
			ПараметрыЭлемента.ПолноеИмя = ЭлементКоллекцииМетаданных.ПолноеИмя();
			ПараметрыЭлемента.Синоним = ЭлементКоллекцииМетаданных.Синоним;
			ПараметрыЭлемента.Родитель = НоваяСтрока;
			ПараметрыЭлемента.Картинка = КартинкаВКонфигураторе(ЭлементКоллекцииМетаданных);
			ДобавитьЭлементДереваОбъектовМетаданных(ПараметрыЭлемента, ЭлементКоллекцииМетаданных.Подсистемы, Ложь);
		КонецЕсли;
	КонецЦикла;
	
	Возврат НоваяСтрока;
	
КонецФункции

&НаСервере
Функция НоваяСтрокаДерева(ПараметрыСтроки, ЭтоОбъектМетаданных = Ложь)
	
	Коллекция = ПараметрыСтроки.Родитель.ПолучитьЭлементы();
	НоваяСтрока = Коллекция.Добавить();
	НоваяСтрока.Имя                 = ПараметрыСтроки.Имя;
	НоваяСтрока.Представление       = ?(ЗначениеЗаполнено(ПараметрыСтроки.Синоним), ПараметрыСтроки.Синоним, ПараметрыСтроки.Имя);
	НоваяСтрока.Картинка            = ПараметрыСтроки.Картинка;
	НоваяСтрока.ПолноеИмя           = ПараметрыСтроки.ПолноеИмя;
	НоваяСтрока.ЭтоОбъектМетаданных = ЭтоОбъектМетаданных;
	НоваяСтрока.Пометка = ?(ВыбранныеОбъектыМетаданных.НайтиПоЗначению(ПараметрыСтроки.ПолноеИмя) <> Неопределено
		Или ЭтоОбъектМетаданных И ВыбранныеОбъектыМетаданных.НайтиПоЗначению(ПараметрыСтроки.Родитель.Имя) <> Неопределено, 1, 0);
	
	Если НоваяСтрока.Пометка
	   И НоваяСтрока.ЭтоОбъектМетаданных
	   И Не ЗначениеЗаполнено(ИдентификаторСтрокиПервогоВыбранногоОбъекта) Тогда
	
		ИдентификаторСтрокиПервогоВыбранногоОбъекта = НоваяСтрока.ПолучитьИдентификатор();
		Если Не ЗначениеЗаполнено(ИдентификаторТекущейСтрокиПриОткрытии) Тогда
			ИдентификаторТекущейСтрокиПриОткрытии = ИдентификаторСтрокиПервогоВыбранногоОбъекта;
		КонецЕсли;
	КонецЕсли;
	
	Если НоваяСтрока.ЭтоОбъектМетаданных 
		И НоваяСтрока.ПолноеИмя = НачальноеЗначениеВыбора Тогда
		ИдентификаторТекущейСтрокиПриОткрытии = НоваяСтрока.ПолучитьИдентификатор();
	КонецЕсли;
	
	Возврат НоваяСтрока;
	
КонецФункции

// Добавляет новую строку в таблицу значений видов объектов метаданных
// конфигурации.
//
// Параметры:
//   Имя  - Строка - имя объекта метаданных или вида объекта метаданных.
//   Синоним - Строка - синоним объекта метаданных.
//   Картинка - Число - картинка поставленная в соответствие объекту метаданных
//                      или виду объекта метаданных.
//   ЭтоКоллекцияОбщие - Булево - признак того, что текущий элемент содержит подэлементы.
//   Таб - ТаблицаЗначений
//
&НаСервере
Процедура КоллекцииОбъектовМетаданных_НоваяСтрока(Имя, Синоним, Картинка, ЭтоКоллекцияОбщие, Таб)
	
	НоваяСтрока = Таб.Добавить();
	НоваяСтрока.Имя               = Имя;
	НоваяСтрока.Синоним           = Синоним;
	НоваяСтрока.Картинка          = Картинка;
	НоваяСтрока.ЭтоКоллекцияОбщие = ЭтоКоллекцияОбщие;
	
КонецПроцедуры

&НаКлиенте
Функция ЗначениеПометкиЭлементов(ЭлементыРодителя)
	
	ЕстьПомеченные    = Ложь;
	ЕстьНепомеченные = Ложь;
	
	Для каждого ЭлементРодителя Из ЭлементыРодителя Цикл
		
		Если ЭлементРодителя.Пометка = 2 ИЛИ (ЕстьПомеченные И ЕстьНепомеченные) Тогда
			ЕстьПомеченные    = Истина;
			ЕстьНепомеченные = Истина;
			Прервать;
		ИначеЕсли ЭлементРодителя.ЭтоОбъектМетаданных Тогда
			ЕстьПомеченные    = ЕстьПомеченные    ИЛИ    ЭлементРодителя.Пометка;
			ЕстьНепомеченные = ЕстьНепомеченные ИЛИ НЕ ЭлементРодителя.Пометка;
		Иначе
			ВложенныеЭлементы = ЭлементРодителя.ПолучитьЭлементы();
			Если ВложенныеЭлементы.Количество() = 0 Тогда
				Продолжить;
			КонецЕсли;
			ЗначениеПометкиВложенныхЭлементов = ЗначениеПометкиЭлементов(ВложенныеЭлементы);
			ЕстьПомеченные    = ЕстьПомеченные    ИЛИ    ЭлементРодителя.Пометка ИЛИ    ЗначениеПометкиВложенныхЭлементов;
			ЕстьНепомеченные = ЕстьНепомеченные ИЛИ НЕ ЭлементРодителя.Пометка ИЛИ НЕ ЗначениеПометкиВложенныхЭлементов;
		КонецЕсли;
	КонецЦикла;
	
	Если ЕстьПомеченные Тогда
		Если ЕстьНепомеченные Тогда
			Возврат 2;
		Иначе
			Если ТолькоПодсистемыСКИ Тогда
				Возврат 2;
			Иначе
				Возврат 1;
			КонецЕсли;
		КонецЕсли;
	Иначе
		Возврат 0;
	КонецЕсли;
	
КонецФункции

&НаСервере
Процедура ПометитьЭлементыРодителейНаСервере(Элемент)

	Родитель = Элемент.ПолучитьРодителя();
	
	Если Родитель = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ЭлементыРодителя = Родитель.ПолучитьЭлементы();
	Если ЭлементыРодителя.Количество() = 0 Тогда
		Родитель.Пометка = 0;
	ИначеЕсли Элемент.Пометка = 2 Тогда
		Родитель.Пометка = 2;
	Иначе
		Родитель.Пометка = ЗначениеПометкиЭлементовНаСервере(ЭлементыРодителя);
	КонецЕсли;
	
	ПометитьЭлементыРодителейНаСервере(Родитель);

КонецПроцедуры

&НаСервере
Функция ЗначениеПометкиЭлементовНаСервере(ЭлементыРодителя)
	
	ЕстьПомеченные    = Ложь;
	ЕстьНепомеченные = Ложь;
	
	Для каждого ЭлементРодителя Из ЭлементыРодителя Цикл
		
		Если ЭлементРодителя.Пометка = 2 ИЛИ (ЕстьПомеченные И ЕстьНепомеченные) Тогда
			ЕстьПомеченные    = Истина;
			ЕстьНепомеченные = Истина;
			Прервать;
		ИначеЕсли ЭлементРодителя.ЭтоОбъектМетаданных Тогда
			ЕстьПомеченные    = ЕстьПомеченные    ИЛИ    ЭлементРодителя.Пометка;
			ЕстьНепомеченные = ЕстьНепомеченные ИЛИ НЕ ЭлементРодителя.Пометка;
		Иначе
			ВложенныеЭлементы = ЭлементРодителя.ПолучитьЭлементы();
			Если ВложенныеЭлементы.Количество() = 0 Тогда
				Продолжить;
			КонецЕсли;
			ЗначениеПометкиВложенныхЭлементов = ЗначениеПометкиЭлементовНаСервере(ВложенныеЭлементы);
			ЕстьПомеченные    = ЕстьПомеченные    ИЛИ    ЭлементРодителя.Пометка ИЛИ    ЗначениеПометкиВложенныхЭлементов;
			ЕстьНепомеченные = ЕстьНепомеченные ИЛИ НЕ ЭлементРодителя.Пометка ИЛИ НЕ ЗначениеПометкиВложенныхЭлементов;
		КонецЕсли;
	КонецЦикла;
	
	Возврат ?(ЕстьПомеченные И ЕстьНепомеченные, 2, ?(ЕстьПомеченные, 1, 0));
	
КонецФункции

// Процедура НачальнаяПометкаКоллекций устанавливает пометку для коллекций
// объектов метаданных, которые не имеют объектов метаданных (истина) и 
// которые имеют объекты метаданных с заданной пометкой.
//
// Параметры:
//   Элемент      - ДанныеФормыКоллекцияЭлементовДерева.
//
&НаСервере
Процедура НачальнаяПометкаКоллекций(Родитель)
	
	ВложенныеЭлементы = Родитель.ПолучитьЭлементы();
	
	Для Каждого ВложенныйЭлемент Из ВложенныеЭлементы Цикл
		Если ВложенныйЭлемент.Пометка Тогда
			ПометитьЭлементыРодителейНаСервере(ВложенныйЭлемент);
		КонецЕсли;
		НачальнаяПометкаКоллекций(ВложенныйЭлемент);
	КонецЦикла;
	
КонецПроцедуры

&НаСервереБезКонтекста
Процедура ВыбратьСсылки(ВыбранныеОбъектыМетаданных)
	
	Если ВыбранныеОбъектыМетаданных.Количество() = 0 Тогда 
		Возврат;
	КонецЕсли;
	
	ОписаниеОбъектовМетаданных = ВыбранныеОбъектыМетаданных.ВыгрузитьЗначения();
	Ссылки = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ОписаниеОбъектовМетаданных, Ложь);
	
	ТекущийИндекс = ВыбранныеОбъектыМетаданных.Количество() - 1;
	Пока ТекущийИндекс >= 0 Цикл
		ЭлементСписка = ВыбранныеОбъектыМетаданных[ТекущийИндекс];
		Ссылка = Ссылки[ЭлементСписка.Значение];
		Если Ссылка <> Неопределено Тогда 
			ЭлементСписка.Значение = Ссылка;
		Иначе
			ВыбранныеОбъектыМетаданных.Удалить(ЭлементСписка);
		КонецЕсли;
		ТекущийИндекс = ТекущийИндекс - 1;
	КонецЦикла;
	
КонецПроцедуры

&НаСервере
Процедура ДеревоОбъектовМетаданныхЗаполнитьПоРазделам()
	
	ДеревоОбъектовМетаданных.ПолучитьЭлементы().Очистить();
	
	Ветка = ДеревоОбъектовМетаданных.ПолучитьЭлементы().Добавить();
	Ветка.Имя = Метаданные.Имя;
	Ветка.Представление = Метаданные.Синоним;
	Ветка.Адрес = ".";
	
	ВывестиКоллекцию(Ветка, Метаданные.Подсистемы);
	
КонецПроцедуры

&НаСервере
Процедура ВывестиКоллекцию(Знач Ветка, Знач КоллекцияОбъектовМетаданных)
	
	Для Каждого ОбъектМетаданных Из КоллекцияОбъектовМетаданных Цикл
		Если ТипЗнч(Ветка) = Тип("ДанныеФормыЭлементДерева") И ОбъектМетаданных.ПолноеИмя() = Ветка.ПолноеИмя Тогда
			Продолжить;
		КонецЕсли;
		
		Если Не ОбъектМетаданныхДоступен(ОбъектМетаданных) Тогда
			Продолжить;
		КонецЕсли;
		
		НоваяВетка = Ветка.ПолучитьЭлементы().Добавить();
		НоваяВетка.Имя = ОбъектМетаданных.Имя;
		НоваяВетка.ПолноеИмя = ОбъектМетаданных.ПолноеИмя();
		НоваяВетка.Представление = ОбъектМетаданных.Представление();
		НоваяВетка.Картинка = КартинкаВИнтерфейсе(ОбъектМетаданных);
		НоваяВетка.Адрес = ?(ТипЗнч(Ветка) = Тип("ДанныеФормыЭлементДерева"), Ветка.Адрес + "/", "") + НоваяВетка.Представление;
		
		Если ЗначениеЗаполнено(АдресаВыбранныхОбъектов) Тогда
			НоваяВетка.Пометка = ?(АдресаВыбранныхОбъектов.НайтиПоЗначению(НоваяВетка.Адрес) = Неопределено, 0, 1);
		Иначе
			НоваяВетка.Пометка = ?(ВыбранныеОбъектыМетаданных.НайтиПоЗначению(НоваяВетка.ПолноеИмя) = Неопределено, 0, 1);
		КонецЕсли;
		
		Если ЭтоПодсистема(ОбъектМетаданных) Тогда
			ВывестиКоллекцию(НоваяВетка, ОбъектМетаданных.Состав);
			ВывестиКоллекцию(НоваяВетка, ОбъектМетаданных.Подсистемы);
			НоваяВетка.ЭтоПодраздел = КоллекцияОбъектовМетаданных <> Метаданные.Подсистемы;
		Иначе
			НоваяВетка.ЭтоОбъектМетаданных = Истина;
			
			Если ОбщегоНазначения.ЭтоЖурналДокументов(ОбъектМетаданных) Тогда
				ВывестиКоллекцию(НоваяВетка, ОбъектМетаданных.РегистрируемыеДокументы);
			ИначеЕсли ОбщегоНазначения.ЭтоСправочник(ОбъектМетаданных) Тогда 
				ВывестиКоллекцию(НоваяВетка, ПодчиненныеСправочники(ОбъектМетаданных));
			КонецЕсли;
		КонецЕсли;
		
		Если ЭтоПодсистема(ОбъектМетаданных) И НоваяВетка.ПолучитьЭлементы().Количество() = 0 Тогда
			Индекс = Ветка.ПолучитьЭлементы().Индекс(НоваяВетка);
			Ветка.ПолучитьЭлементы().Удалить(Индекс);
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

&НаСервере
Функция КартинкаВИнтерфейсе(ОбъектМетаданных)
	
	СвойстваОбъекта = Новый Структура("Картинка");
	ЗаполнитьЗначенияСвойств(СвойстваОбъекта, ОбъектМетаданных);
	Если ЗначениеЗаполнено(СвойстваОбъекта.Картинка) Тогда
		Возврат СвойстваОбъекта.Картинка;
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

&НаСервере
Функция КартинкаВКонфигураторе(ОбъектМетаданных)
	
	ВидОбъекта = СтрРазделить(ОбъектМетаданных.ПолноеИмя(), ".")[0];
	Картинки = Новый Структура(ВидОбъекта);
	ЗаполнитьЗначенияСвойств(Картинки, БиблиотекаКартинок);
	
	Возврат Картинки[ВидОбъекта];
	
КонецФункции

&НаСервереБезКонтекста
Функция ЭтоПодсистема(ОбъектМетаданных)
	Возврат СтрНачинаетсяС(ОбъектМетаданных.ПолноеИмя(), "Подсистема");
КонецФункции

&НаСервере
Функция ОбъектМетаданныхДоступен(ОбъектМетаданных)
	
	ЭтоПодсистема = ЭтоПодсистема(ОбъектМетаданных);
	ЭтоЖурналДокументов = ОбщегоНазначения.ЭтоЖурналДокументов(ОбъектМетаданных);
	
	Если Не ЭтоПодсистема Тогда
		ЭтоВыбираемыйОбъект = Не ЗначениеЗаполнено(КоллекцииВыбираемыхОбъектовМетаданных);
		Для Каждого ВидОбъекта Из КоллекцииВыбираемыхОбъектовМетаданных.ВыгрузитьЗначения() Цикл
			Если Метаданные[ВидОбъекта].Содержит(ОбъектМетаданных) Тогда
				ЭтоВыбираемыйОбъект = Истина;
				Прервать;
			КонецЕсли;
		КонецЦикла;
		
		Если Не ЭтоВыбираемыйОбъект Тогда
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	
	Если Не ОбщегоНазначения.ЭтоСправочник(ОбъектМетаданных)
		И Не ОбщегоНазначения.ЭтоДокумент(ОбъектМетаданных)
		И Не ЭтоЖурналДокументов
		И Не ОбщегоНазначения.ЭтоПланВидовХарактеристик(ОбъектМетаданных)
		И Не ОбщегоНазначения.ЭтоРегистрСведений(ОбъектМетаданных)
		И Не ОбщегоНазначения.ЭтоРегистрБухгалтерии(ОбъектМетаданных)
		И Не ОбщегоНазначения.ЭтоРегистрНакопления(ОбъектМетаданных)
		И Не ОбщегоНазначения.ЭтоРегистрРасчета(ОбъектМетаданных)
		И Не ОбщегоНазначения.ЭтоПланВидовХарактеристик(ОбъектМетаданных)
		И Не ОбщегоНазначения.ЭтоПланСчетов(ОбъектМетаданных)
		И Не ОбщегоНазначения.ЭтоПланВидовРасчета(ОбъектМетаданных)
		И Не ОбщегоНазначения.ЭтоБизнесПроцесс(ОбъектМетаданных)
		И Не ОбщегоНазначения.ЭтоЗадача(ОбъектМетаданных)
		И Не ЭтоПодсистема Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ФильтрПоОбъектамМетаданных)
		И Не ЭтоПодсистема
		И Не ЭтоЖурналДокументов
		И ФильтрПоОбъектамМетаданных.НайтиПоЗначению(ОбъектМетаданных.ПолноеИмя()) = Неопределено Тогда
		Возврат Ложь;
	КонецЕсли;
	
	ДоступенПоПравам = ПравоДоступа("Просмотр", ОбъектМетаданных);
	ДоступенПоФункциональнымОпциям = ОбщегоНазначения.ОбъектМетаданныхДоступенПоФункциональнымОпциям(ОбъектМетаданных);
	
	СвойстваМетаданного = Новый Структура("ПолнотекстовыйПоиск, ВключатьВКомандныйИнтерфейс");
	ЗаполнитьЗначенияСвойств(СвойстваМетаданного, ОбъектМетаданных);
	
	Если СвойстваМетаданного.ПолнотекстовыйПоиск = Неопределено Тогда 
		ИспользованиеПолнотекстовогоПоиска = Истина; // Если свойства нет - игнорируем.
	Иначе 
		ИспользованиеПолнотекстовогоПоиска = (СвойстваМетаданного.ПолнотекстовыйПоиск = 
			Метаданные.СвойстваОбъектов.ИспользованиеПолнотекстовогоПоиска.Использовать);
	КонецЕсли;
	
	Если СвойстваМетаданного.ВключатьВКомандныйИнтерфейс = Неопределено Тогда 
		ВключатьВКомандныйИнтерфейс = Истина; // Если свойства нет - игнорируем.
	Иначе 
		ВключатьВКомандныйИнтерфейс = СвойстваМетаданного.ВключатьВКомандныйИнтерфейс;
	КонецЕсли;
	
	Возврат ДоступенПоПравам И ДоступенПоФункциональнымОпциям 
		И ИспользованиеПолнотекстовогоПоиска И ВключатьВКомандныйИнтерфейс;
	
КонецФункции

&НаСервере
Функция ПодчиненныеСправочники(ОбъектМетаданных)
	
	Если ПодчиненныеСправочники = Неопределено Тогда
		ПодчиненныеСправочники = Новый Соответствие;
		
		Для Каждого Справочник Из Метаданные.Справочники Цикл
			Если ПодчиненныеСправочники[Справочник] = Неопределено Тогда
				ПодчиненныеСправочники[Справочник] = Новый Массив;
			КонецЕсли;
			Для Каждого ВладелецСправочника Из Справочник.Владельцы Цикл
				Если ПодчиненныеСправочники[ВладелецСправочника] = Неопределено Тогда
					ПодчиненныеСправочники[ВладелецСправочника] = Новый Массив;
				КонецЕсли;
				СписокСправочников = ПодчиненныеСправочники[ВладелецСправочника]; // Массив
				СписокСправочников.Добавить(Справочник);
			КонецЦикла;
		КонецЦикла;
	КонецЕсли;
	
	Возврат ПодчиненныеСправочники[ОбъектМетаданных];
	
КонецФункции

&НаКлиенте
Процедура ЗаполнитьДеревоОбъектов(ПриОткрытии = Ложь)
	
	ИдентификаторыРазворачиваемыхСтрок = Новый Массив;
	ЗаполнитьДеревоОбъектовНаСервере(ПриОткрытии, ИдентификаторыРазворачиваемыхСтрок);
	
	Если ПриОткрытии
	   И (РодительскиеПодсистемы.Количество() > 0
	      Или КоллекцииВыбираемыхОбъектовМетаданных.Количество() = 1) Тогда
		
		Элементы.ДеревоОбъектовМетаданных.Развернуть(ИдентификаторыРазворачиваемыхСтрок[0], Истина);
		Возврат;
	КонецЕсли;
	
	Для Каждого ИдентификаторСтроки Из ИдентификаторыРазворачиваемыхСтрок Цикл
		Элементы.ДеревоОбъектовМетаданных.Развернуть(ИдентификаторСтроки);
	КонецЦикла;
	
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьДеревоОбъектовНаСервере(ПриОткрытии, ИдентификаторыРазворачиваемыхСтрок)
	
	ИдентификаторТекущейСтрокиПриОткрытии = 0;
	ИдентификаторСтрокиПервогоВыбранногоОбъекта = 0;
	
	Если СпособГруппировкиОбъектов = "ПоРазделам" Тогда
		ДеревоОбъектовМетаданныхЗаполнитьПоРазделам();
	Иначе
		ДеревоОбъектовМетаданныхЗаполнить();
	КонецЕсли;
	
	НачальнаяПометкаКоллекций(ДеревоОбъектовМетаданных);
	
	Если ДеревоОбъектовМетаданных.ПолучитьЭлементы().Количество() < 1 Тогда
		Возврат;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ИдентификаторСтрокиПервогоВыбранногоОбъекта) Тогда
		Строка = ДеревоОбъектовМетаданных.НайтиПоИдентификатору(ИдентификаторСтрокиПервогоВыбранногоОбъекта);
		Пока Строка <> Неопределено Цикл
			ИдентификаторыРазворачиваемыхСтрок.Вставить(0, Строка.ПолучитьИдентификатор());
			Строка = Строка.ПолучитьРодителя();
		КонецЦикла;
	Иначе
		ИдентификаторКорня = ДеревоОбъектовМетаданных.ПолучитьЭлементы()[0].ПолучитьИдентификатор();
		ИдентификаторыРазворачиваемыхСтрок.Добавить(ИдентификаторКорня);
	КонецЕсли;
	
	// Устанавливаем начальное значение выбора.
	Если (ПриОткрытии Или Не ПометкаВыполнялась)
	   И ИдентификаторТекущейСтрокиПриОткрытии > 0 Тогда
		
		Элементы.ДеревоОбъектовМетаданных.ТекущаяСтрока = ИдентификаторТекущейСтрокиПриОткрытии;
		
	ИначеЕсли ЗначениеЗаполнено(ИдентификаторСтрокиПервогоВыбранногоОбъекта) Тогда
		
		Элементы.ДеревоОбъектовМетаданных.ТекущаяСтрока = ИдентификаторСтрокиПервогоВыбранногоОбъекта;
	КонецЕсли;
	
КонецПроцедуры

#Область ПометкаЭлементов

// Параметры:
//  ЭлементДерева - ДанныеФормыЭлементДерева:
//      * Пометка             - Число  - обязательный реквизит дерева.
//      * ЭтоОбъектМетаданных - Булево - обязательный реквизит дерева.
//
&НаКлиентеНаСервереБезКонтекста
Процедура ПриПометкеЭлементаДерева(ЭлементДерева)
	
	ЭлементДерева.Пометка = СледующееЗначениеПометкиЭлемента(ЭлементДерева);
	
	Если ТребуетсяПометитьВложенныеЭлементы(ЭлементДерева) Тогда 
		ПометитьВложенныеЭлементыРекурсивно(ЭлементДерева);
	КонецЕсли;
	
	Если ЭлементДерева.Пометка = ПометкаФлажокНеУстановлен() Тогда 
		ЭлементДерева.Пометка = ЗначениеПометкиОтносительноВложенныхЭлементов(ЭлементДерева);
	КонецЕсли;
	
	ПометитьЭлементыРодителейРекурсивно(ЭлементДерева);
	
КонецПроцедуры

&НаКлиентеНаСервереБезКонтекста
Функция ПометкаФлажокНеУстановлен()
	
	Возврат 0;
	
КонецФункции

&НаКлиентеНаСервереБезКонтекста
Функция ПометкаФлажокУстановлен()
	
	Возврат 1;
	
КонецФункции

&НаКлиентеНаСервереБезКонтекста
Функция ПометкаКвадрат()
	
	Возврат 2;
	
КонецФункции

// Параметры:
//  ЭлементДерева - ДанныеФормыЭлементДерева:
//      * Пометка             - Число  - обязательный реквизит дерева.
//      * ЭтоОбъектМетаданных - Булево - обязательный реквизит дерева.
//
&НаКлиентеНаСервереБезКонтекста
Функция СледующееЗначениеПометкиЭлемента(ЭлементДерева)
	
	// 0 - Флажок не установлен.
	// 1 - Флажок установлен.
	// 2 - Установлен квадрат.
	//
	// Переопределение графа конечного автомата (или машины состояний, как ее еще можно назвать).
	//
	// Платформа делает постоянный цикл при изменении пометки,
	// т.е. имеет компоненту сильной связности орграфа:
	// 0-1-2-0-1-2-0-1...
	//
	//    0
	//   / \
	//  2 - 1
	//
	// т.е. совершает цикл: не помеченный - помеченный - квадрат - не помеченный.
	//
	// Нам требуется поведение недетерминированного конечного автомата с компонентой сильной связности:
	// 0-1-0-1-0...
	//
	// т.е. помеченный должен переходить в не помеченный, а тот - опять в помеченный.
	//
	// При этом:
	//
	// Для разделов циклы:
	// 1) 1-0-1-0-1...
	// 2) 2-0-1-0-1-0-...
	//
	//      /\
	// 2 - 0 -1
	//
	// т.е. с квадрата должен быть переход к неустановленному флажку.
	//
	// Для метаданных циклы:
	// 1) 1-0-1-0-1-0...
	// 2) 2-1-0-1-0-1-0...
	//
	//      /\
	// 2 - 1 -0
	//
	// т.е. с квадрата должен быть переход к установленному флажку.
	
	// На момент проверки платформа уже изменила значение пометки.
	
	Если ЭлементДерева.ЭтоОбъектМетаданных Тогда
		// Предыдущее значение пометки = 2 : Установлен квадрат.
		Если ЭлементДерева.Пометка = 0 Тогда
			Возврат ПометкаФлажокУстановлен();
		КонецЕсли;
	КонецЕсли;
	
	// Предыдущее значение пометки = 1 : Флажок установлен.
	Если ЭлементДерева.Пометка = 2 Тогда 
		Возврат ПометкаФлажокНеУстановлен();
	КонецЕсли;
	
	// Во всех остальных случаях - значение установленное платформой.
	Возврат ЭлементДерева.Пометка;
	
КонецФункции

// Параметры:
//  ЭлементДерева - ДанныеФормыЭлементДерева:
//      * Пометка             - Число  - обязательный реквизит дерева.
//      * ЭтоОбъектМетаданных - Булево - обязательный реквизит дерева.
//
&НаКлиентеНаСервереБезКонтекста
Процедура ПометитьЭлементыРодителейРекурсивно(ЭлементДерева)
	
	Родитель = ЭлементДерева.ПолучитьРодителя();
	
	Если Родитель = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ЭлементыРодителя = Родитель.ПолучитьЭлементы();
	Если ЭлементыРодителя.Количество() = 0 Тогда
		Родитель.Пометка = ПометкаФлажокУстановлен();
	ИначеЕсли ЭлементДерева.Пометка = ПометкаКвадрат() Тогда
		Родитель.Пометка = ПометкаКвадрат();
	Иначе
		Родитель.Пометка = ЗначениеПометкиОтносительноВложенныхЭлементов(Родитель);
	КонецЕсли;
	
	ПометитьЭлементыРодителейРекурсивно(Родитель);
	
КонецПроцедуры

// Параметры:
//  ЭлементДерева - ДанныеФормыЭлементДерева:
//      * Пометка             - Число  - обязательный реквизит дерева.
//      * ЭтоОбъектМетаданных - Булево - обязательный реквизит дерева.
//
&НаКлиентеНаСервереБезКонтекста
Функция ЗначениеПометкиОтносительноВложенныхЭлементов(ЭлементДерева)
	
	СостояниеВложенныхЭлементов = СостояниеВложенныхЭлементов(ЭлементДерева);
	
	ЕстьПомеченные   = СостояниеВложенныхЭлементов.ЕстьПомеченные;
	ЕстьНепомеченные = СостояниеВложенныхЭлементов.ЕстьНепомеченные;
	
	Если ЭлементДерева.ЭтоОбъектМетаданных Тогда 
		
		// Для объекта метаданных важно какое у него состояние сейчас,
		// ведь этот объект метаданных надо возвращать.
		// Нельзя сбрасывать установленный флажок.
		
		Если ЭлементДерева.Пометка = ПометкаФлажокУстановлен() Тогда 
			// Оставляем флажок взведенным независимо от вложенных.
			Возврат ПометкаФлажокУстановлен();
		КонецЕсли;
		
		Если ЭлементДерева.Пометка = ПометкаФлажокНеУстановлен()
			Или ЭлементДерева.Пометка = ПометкаКвадрат() Тогда 
			
			Если ЕстьПомеченные Тогда
				Возврат ПометкаКвадрат();
			Иначе 
				Возврат ПометкаФлажокНеУстановлен();
			КонецЕсли;
		КонецЕсли;
		
	Иначе 
		
		// Для разделов не важно какое состояние сейчас, 
		// они всегда зависят только от вложенных.
		
		Если ЕстьПомеченные Тогда
			
			Если ЕстьНепомеченные Тогда
				Возврат ПометкаКвадрат();
			Иначе
				Возврат ПометкаФлажокУстановлен();
			КонецЕсли;
			
		КонецЕсли;
		
		Возврат ПометкаФлажокНеУстановлен();
		
	КонецЕсли;
	
КонецФункции

// Параметры:
//  ЭлементДерева - ДанныеФормыЭлементДерева:
//      * Пометка             - Число  - обязательный реквизит дерева.
//      * ЭтоОбъектМетаданных - Булево - обязательный реквизит дерева.
//
&НаКлиентеНаСервереБезКонтекста
Функция СостояниеВложенныхЭлементов(ЭлементДерева)
	
	ВложенныеЭлементы = ЭлементДерева.ПолучитьЭлементы();
	
	ЕстьПомеченные   = Ложь;
	ЕстьНепомеченные = Ложь;
	
	Для каждого ВложенныйЭлемент Из ВложенныеЭлементы Цикл
		
		Если ВложенныйЭлемент.Пометка = ПометкаФлажокНеУстановлен() Тогда 
			ЕстьНепомеченные = Истина;
			Продолжить;
		КонецЕсли;
		
		Если ВложенныйЭлемент.Пометка = ПометкаФлажокУстановлен() Тогда 
			ЕстьПомеченные = Истина;
			
			Если ВложенныйЭлемент.ЭтоОбъектМетаданных Тогда 
				
				// Для объекта метаданных допустимо иметь непомеченные в своем составе вложенных,
				// при этом самостоятельно быть помеченным. Чтобы обыграть эту ситуацию надо поднять
				// вложенные элементы на один уровень с самим объектом, к которому они относятся.
				
				Состояние = СостояниеВложенныхЭлементов(ВложенныйЭлемент);
				ЕстьПомеченные   = ЕстьПомеченные   Или Состояние.ЕстьПомеченные;
				ЕстьНепомеченные = ЕстьНепомеченные Или Состояние.ЕстьНепомеченные;
			КонецЕсли;
			
			Продолжить;
		КонецЕсли;
		
		Если ВложенныйЭлемент.Пометка = ПометкаКвадрат() Тогда 
			ЕстьПомеченные   = Истина;
			ЕстьНепомеченные = Истина;
			Продолжить;
		КонецЕсли;
		
	КонецЦикла;
	
	Результат = Новый Структура;
	Результат.Вставить("ЕстьПомеченные",   ЕстьПомеченные);
	Результат.Вставить("ЕстьНепомеченные", ЕстьНепомеченные);
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//  ЭлементДерева - ДанныеФормыЭлементДерева:
//      * Пометка             - Число  - обязательный реквизит дерева.
//      * ЭтоОбъектМетаданных - Булево - обязательный реквизит дерева.
//
&НаКлиентеНаСервереБезКонтекста
Функция ТребуетсяПометитьВложенныеЭлементы(ЭлементДерева)
	
	Если ЭлементДерева.ЭтоОбъектМетаданных Тогда 
		
		// Если для объекта метаданных есть не полностью выбранные вложенные элементы,
		// значит эти элементы были выбраны пользователем и не следует портить его выбор.
		
		СостояниеВложенныхЭлементов = СостояниеВложенныхЭлементов(ЭлементДерева);
		
		ЕстьПомеченные   = СостояниеВложенныхЭлементов.ЕстьПомеченные;
		ЕстьНепомеченные = СостояниеВложенныхЭлементов.ЕстьНепомеченные;
		
		Если ЕстьПомеченные И ЕстьНепомеченные Тогда 
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

// Параметры:
//  ЭлементДерева - ДанныеФормыЭлементДерева:
//      * Пометка             - Число  - обязательный реквизит дерева.
//      * ЭтоОбъектМетаданных - Булево - обязательный реквизит дерева.
//
&НаКлиентеНаСервереБезКонтекста
Процедура ПометитьВложенныеЭлементыРекурсивно(ЭлементДерева)
	
	ВложенныеЭлементы = ЭлементДерева.ПолучитьЭлементы();
	
	Для каждого ВложенныйЭлемент Из ВложенныеЭлементы Цикл
		
		ВложенныйЭлемент.Пометка = ЭлементДерева.Пометка;
		ПометитьВложенныеЭлементыРекурсивно(ВложенныйЭлемент);
		
	КонецЦикла;
	
КонецПроцедуры

// Параметры:
//  ЭлементДеревоРазделовПоиска - ДанныеФормыЭлементДерева:
//      * Пометка             - Число  - обязательный реквизит дерева.
//      * ЭтоОбъектМетаданных - Булево - обязательный реквизит дерева.
//  ЗначениеПометки - Число - устанавливаемое значение.
//
&НаКлиентеНаСервереБезКонтекста
Процедура ПометитьВсеЭлементыДереваРекурсивно(ЭлементДеревоРазделовПоиска, ЗначениеПометки)
	
	КоллекцияЭлементовДерева = ЭлементДеревоРазделовПоиска.ПолучитьЭлементы();
	
	Для каждого ЭлементДерева Из КоллекцияЭлементовДерева Цикл
		ЭлементДерева.Пометка = ЗначениеПометки;
		ПометитьВсеЭлементыДереваРекурсивно(ЭлементДерева, ЗначениеПометки);
	КонецЦикла;
	
КонецПроцедуры

#КонецОбласти

&НаСервере
Процедура УстановитьУсловноеОформление()
	
	УсловноеОформление.Элементы.Очистить();
	
	Элемент = УсловноеОформление.Элементы.Добавить();
	
	ПолеЭлемента = Элемент.Поля.Элементы.Добавить();
	ПолеЭлемента.Поле = Новый ПолеКомпоновкиДанных("ДеревоОбъектовМетаданных");
	
	ОтборЭлемента = Элемент.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
	ОтборЭлемента.ЛевоеЗначение  = Новый ПолеКомпоновкиДанных("ДеревоОбъектовМетаданных.ЭтоПодраздел");
	ОтборЭлемента.ВидСравнения   = ВидСравненияКомпоновкиДанных.Равно;
	ОтборЭлемента.ПравоеЗначение = Истина;
	
	Элемент.Оформление.УстановитьЗначениеПараметра("ЦветТекста", ЦветаСтиля.ЦветРазделаПанелиФункций);
	
КонецПроцедуры

&НаКлиенте
Функция ВыбранныеЭлементы(Ветка)
	
	Результат = Новый Соответствие;
	
	Для Каждого Элемент Из Ветка.ПолучитьЭлементы() Цикл
		Если СпособГруппировкиОбъектов = "ПоВидам"
		   И ВыбиратьКоллекцииКогдаВыбраныВсеОбъекты
		   И Элемент.Пометка = 1
		   И (Элемент.ЭтоКоллекцияОбъектов
		      Или Ветка = ДеревоОбъектовМетаданных) Тогда
			
			Если Элемент.ЭтоКоллекцияОбъектов Тогда
				Результат.Вставить(Элемент.Имя, Элемент.Представление);
			Иначе
				Результат.Вставить("Конфигурация", НСтр("ru = 'Конфигурация'"));
			КонецЕсли;
			Продолжить;
		КонецЕсли;
		Если Элемент.Пометка = 1 И Не ПустаяСтрока(Элемент.ПолноеИмя) И Элемент.ЭтоОбъектМетаданных Тогда
			Результат.Вставить(Элемент.ПолноеИмя, ?(ЗапоминатьРазделыВыбранныхОбъектов
				И СпособГруппировкиОбъектов = "ПоРазделам", Элемент.Адрес, Элемент.Представление));
		КонецЕсли;
		Для Каждого ВыбранныйЭлемент Из ВыбранныеЭлементы(Элемент) Цикл
			Результат.Вставить(ВыбранныйЭлемент.Ключ, ВыбранныйЭлемент.Значение);
		КонецЦикла;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

&НаКлиенте
Процедура ОбновитьКоллекциюВыбранныеОбъектыМетаданных()
	
	ВыбранныеОбъектыМетаданных.Очистить();
	Для Каждого ВыбранныйЭлемент Из ВыбранныеЭлементы(ДеревоОбъектовМетаданных) Цикл
		ВыбранныеОбъектыМетаданных.Добавить(ВыбранныйЭлемент.Ключ, ВыбранныйЭлемент.Значение, Истина);
	КонецЦикла;
	
КонецПроцедуры

#КонецОбласти
